#include "Sock.hpp"
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fstream>
#define WWWROOT "./wwwroot/"    //根目录的路径
#define HOME_PAGE "index.html"  //首页的名字

void Usage(std::string proc)
{
    std::cout << "Usage: " << proc << " port" << std::endl;
}

//验证GET 和 POST方法
//线程的例程函数-处理发送的请求
void* HandlerHttpRequest(void* args)
{
    int sock = *(int *)args;
    delete (int *)args;
    pthread_detach(pthread_self());

    #define SIZE 1024 * 5
    char buffer[SIZE];
    memset(buffer, 0, sizeof(buffer));

    // 这种读法是不正确的，只不过在现在没有被暴露出来罢了
    ssize_t s = recv(sock, buffer, sizeof(buffer), 0);
    if (s > 0)
    {
        buffer[s] = 0;//把读取到的内容当成字符串
        std::cout << buffer<<std::endl; //查看http的请求格式! for test

        std::string html_file = WWWROOT;
        html_file += HOME_PAGE;
        // 此时html_file就是index.html的文件所在位置

        //构建响应返回
        std::ifstream in(html_file);//读取该文件
        if (!in.is_open())   //打开失败
        {
            std::string http_response = "http/1.0 404 NOT FOUND\n";//状态行
            http_response += "Content-Type: text/html; charset=utf8\n";//响应的报头
            http_response += "\n";//空行
            http_response += "<html><p>你访问的资源不存在</p></html>";//正文
            send(sock, http_response.c_str(), http_response.size(), 0);
        }
        else //打开成功
        {
            std::cout << "--------read html begin---------" << std::endl;
            struct stat st;
            stat(html_file.c_str(), &st);

            std::string http_response = "http/1.0 307 Temporary Redirect\n"; //响应行

            //构建报头信息
            // Content-Type代表的是正文部分的数据类型
            http_response += "Content-Type: text/html; charset=utf8\n";
            http_response += "Content-Length: ";
            http_response += std::to_string(st.st_size);//整数->字符串
            http_response += "\n";

            //增加Set-Cookie报头属性
            //也可以写成: 
            http_response +="Set-Cookie: id=11111&&password=2222\n";
            // http_response += "Set-Cookie: id=11111\n";
            // http_response += "Set-Cookie: password=2222\n";

            http_response += "\n";//空行

            //接下来,才是正文的内容
            //此时的正文是网页的内容
            std::string content;
            std::string line;
            while (std::getline(in, line))//从文件流in里面读取网页内容到line中
            {
                content += line;
            }
            http_response += content;//加上正文content
            in.close();
            std::cout << http_response << std::endl;//把响应打印出来观察

            std::cout << "--------read html end---------" << std::endl;
            //发送响应
            send(sock, http_response.c_str(), http_response.size(), 0);
        }
    }

    close(sock);
    return nullptr;
}

//之后我们是这样启动程序的: ./HTTP 服务器的端口号
int main(int argc,char* argv[])
{
    if(argc!=2)
    {
        Usage(argv[0]);
        exit(1);
    }
    uint16_t port = atoi(argv[1]);//拿到端口号
    int listen_sock = Sock::Socket();//创建套接字
    Sock::Bind(listen_sock,port);//将端口号和套接字绑定
    Sock::Listen(listen_sock);//设置套接字为监听状态

    for(;;)
    {
        //主线程不断Accept获取新链接,新线程执行http请求
        int new_sock = Sock::Accept(listen_sock);
        if(new_sock > 0)
        {
            //创建新线程替我们处理请求
            pthread_t tid;
            int* parm = new int(new_sock);
            pthread_create(&tid,nullptr,HandlerHttpRequest,parm);
        }
    }

    return 0;
}

/*
//线程的例程函数-处理发送的请求
void* HandlerHttpRequest(void* args)
{
    int sock = *(int*)args;
    delete (int*)args;

    pthread_detach(pthread_self());//线程分离,后序主线程就不需要等待该线程

    #define SIZE 1024*5
    char buffer[SIZE];
    memset(buffer,0,sizeof(buffer));//把buffer的内容清0

    //读取请求到buffer中
    ssize_t s = recv(sock,buffer,sizeof(buffer),0);
    if(s>0)
    {
        buffer[s] = 0;//把读取到的内容当成字符串,最后放\0
        std::cout << buffer;//查看http的请求格式! 仅仅是for test

        //构建响应返回
        //响应也必须包含3/4部分内容,因为要满足协议,这是规定！！！
        std::string http_response = "http/1.0 200 OK\n";//协议版本 状态码 
        //Content-Type后面的内容表示正文的类型是什么,text/plain:表示正文是普通的文本
        http_response += "Content-Type: text/plain\n"; 
        http_response += "\n"; //传说中的空行->用来区分报头和有效载荷
        http_response += "Mango'http test! Just for Test";//正文

        //发送响应回去
        send(sock, http_response.c_str(), http_response.size(), 0);
    }
    close(sock);//关闭套接字

    return nullptr;
}
*/
